﻿using System;
using System.Dns.Toolkit.DnsServer;
using System.Net.DnsToolkit.Packet;
using System.Net.DnsToolkit.Packet.Busy;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading;

namespace DnsServer.TestUnit {
    [TestClass]
    public class CoreTest {

        [TestMethod]
        public void TestMethod1() {

            var sb = new StringBuilder();
            var dispatcher = new IMessageDispatcherTest.MockMessageDispatcher();
            var byteReceiver = new MockByteReceiver(dispatcher);
            var dnsReader = new MockDnsReader(dispatcher);
            var dnsValidator = new MockDnsValidator(dispatcher);
            var dnsPrinter = new MockDnsPrinter(dispatcher, sb);

            var logger = Console.Out;

            dispatcher.Subscribe(dnsReader, typeof(ByteReceived));
            dispatcher.Subscribe(dnsValidator, typeof(DnsMessageSerialized));
            dispatcher.Subscribe(dnsPrinter, typeof(DnsMessageValidated));

            for (int i = 0; i < 10; i++ ) {
                byteReceiver.Receive(new byte[10]);
            }

            dispatcher.WaitForFinish();
            Assert.AreEqual(10, sb.Length);

        }


        public class ByteReceived { 
            public byte[] Bytes;
            public override string ToString() {
                return BitConverter.ToString(Bytes);
            }
        }
        public class DnsMessageSerialized {
            public IMessage Message;
            public override string ToString() {
                return "IMessage { IHeader { Id = 0x0000; } }";
            }
        }
        public class DnsMessageValidated {
            public IMessage Message;
            public override string ToString() {
                return "IMessage { IHeader { Id = 0x0000; } }";
            }
        }

        class MockByteReceiver : IByteReceiver, ICore {

            public MockByteReceiver(IMessageDispatcher dispatcher) {
                Dispatcher = dispatcher;
            }

            public IMessageDispatcher Dispatcher { private get; set; }
            public void MessageReceived(object o) {
                throw new NotImplementedException();
            }

            public void Receive(byte[] bytes) {
                Console.WriteLine("MockByteReceiver.Receive");
                Dispatcher.Publish(new ByteReceived { Bytes = bytes });
            }

        }

        
        class MockDnsReader : IDnsReader, ICore {

            public MockDnsReader(IMessageDispatcher dispatcher) {
                Dispatcher = dispatcher;
            }

            public IMessageDispatcher Dispatcher { private get; set; }
            public void MessageReceived(object o) {
                var br = (ByteReceived) o;
                Read(br.Bytes, 0, 0);
            }

            public void Read(byte[] bytes, int offset, int size) {
                Console.WriteLine("MockDnsReader.Read");
                Dispatcher.Publish(new DnsMessageSerialized { Message = new Message() });
            }

        }


        class MockDnsValidator : IDnsValidator, ICore {

            public MockDnsValidator(IMessageDispatcher dispatcher) {
                Dispatcher = dispatcher;
            }

            public IMessageDispatcher Dispatcher { private get; set; }
            public void MessageReceived(object dms) {
                Validate(((DnsMessageSerialized)dms).Message);
            }

            public void Validate(IMessage message) {
                Console.WriteLine("MockDnsValidator.Validate");
                Dispatcher.Publish(new DnsMessageValidated { Message = message });
            }

        }


        interface IDnsPrinter {
            void Print(IMessage message);

        }
        class MockDnsPrinter : IDnsPrinter, ICore {

            private readonly StringBuilder _sb;
            public MockDnsPrinter(IMessageDispatcher dispatcher, StringBuilder sb) {
                Dispatcher = dispatcher;
                _sb = sb;
            }

            public IMessageDispatcher Dispatcher { private get; set; }
            public void MessageReceived(object o) {
                var dmv = (DnsMessageValidated)o;
                Print(dmv.Message);
            }

            public void Print(IMessage message) {
                Console.WriteLine("MockDnsPrinter.Print");
                _sb.AppendFormat("IMessage {{ IHeader {{ Id = 0x{0:x4}; }} }}", message.Header.Id);
            }

        }

    }
}
